#include "stdafx.h"
#include "Mouse.h"

#include "Log.h"
#include "Exception.h"
#include "ErrorHandlers.h"
#include "MemUtils.h"

namespace Cvekas {

Mouse::Mouse() 
: v_width(0), v_height(0)
{
	ZeroMemory(mouse, sizeof(mouse));
	ZeroMemory(mouse_current, sizeof(mouse_current));
	ZeroMemory(mouse_last, sizeof(mouse_last));

	LOG("Mouse initialized");
}

Mouse::~Mouse()
{
	LOG("Mouse destroyed");
}

void Mouse::update()
{
	mouse_pos_old = mouse_pos;

	memcpy(mouse_last, mouse, sizeof(mouse));
	memcpy(mouse, mouse_current, sizeof(mouse));
}

bool Mouse::isButtonPressed(MouseButton b) const
{
	return mouse[b];
}

bool Mouse::isButtonUp(MouseButton b) const
{
	return (mouse_last[b] && !mouse[b]);
}

bool Mouse::isButtonDown(MouseButton b) const
{
	return (!mouse_last[b] && mouse[b]);
}

MousePos Mouse::getAbsolutePos() const
{
	return mouse_pos;
}

int Mouse::getRelativeWheel() const
{
	return 0;
}

bool Mouse::process(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	uint16 x, y;

	RECT client;
	if(!::GetClientRect(hWnd, &client))
		throw EXCEPTION("Unable to get client rect");
	r_width = client.right - client.left;
	r_height = client.bottom - client.top;
	if(v_width == 0 && v_height == 0)
	{
		v_width = r_width;
		v_height = r_height;
	}

	switch(message)
	{
	case WM_MOUSEMOVE:
		x = (uint16)(lParam & 0xFFFF);
		y = (uint16)(lParam >> 16);
		mouse_pos.x = (int)(((float)x / (float)r_width) * (float)v_width);
		mouse_pos.y = (int)(((float)y / (float)r_height) * (float)v_height);
		break;

	case WM_LBUTTONDOWN:
		mouse_current[0] = true;
		break;
	case WM_RBUTTONDOWN:
		mouse_current[1] = true;
		break;
	case WM_MBUTTONDOWN:
		mouse_current[2] = true;
		break;

	case WM_LBUTTONUP:
		mouse_current[0] = false;
		break;
	case WM_RBUTTONUP:
		mouse_current[1] = false;
		break;
	case WM_MBUTTONUP:
		mouse_current[2] = false;
		break;

	default:
		return false;
	}
	return true;
}

} // namespace